Spring相关核心知识点

您所在的位置:网站首页 spring 自动注入失效 Spring相关核心知识点

Spring相关核心知识点

2023-05-24 19:34| 来源: 网络整理| 查看: 265

1.1 说一说对Spring中IOC的理解

IOC即“控制反转”,不是什么技术,而是一种设计思想。IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制

谁控制谁,控制什么:传统Java程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOC容器来控制对象的创建

为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转

简单来说IOC控制反转指的就是对象控制权力的转移 , 以前是由程序员自己创建对象自己管理对象 , 使用Spring之后由Spring帮助我们创建对象 , 管理对象, 对象的控制权就转移到Spring框架了 , 所以叫控制反转

1.2 Spring中有哪些依赖注入的方式

所谓依赖注入就是在 Spring IOC 容器创建对象的过程中,将所依赖的对象通过配置进行注入。我们可以通过依赖注入的方式来降低对象间的耦合度

依赖注入分为Setter方 法注入(Setter Injection)和构造器注入(Constructor Injection)和 注解注入三种方式

1.3 说一说对Spring中AOP的理解

AOP就是我们常说的面向切面编程。使用AOP可以将系统中的一些公共模块抽取出来,减少公共模块和业务代码的耦合。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各 部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率  

像Spring中的事物控制使用的就是AOP机制实现的 , 同时也可以使用AOP做一些权限控制 , 日志记录 , 接口统一缓存等操作

Spring中的AOP底层主要是通过动态代理机制实现的 , 主要使用的是JDK动态代理和CGLIB动态代理

1.4 Spring中AOP的原理了解过嘛

在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类

JDK 动态代理是基于接口的代理 , 产生的代理对象和目标对象实现了相同的接口 , 创建代理对象的方法

Object proxy = Proxy.newProxyInstance(类加载器,目标对象接口, 代理执行器InvocationHandler)

CGLIB动态代理是基于父类的代理 , 产生的代理对象是目标对象的子类 , 创建代理对象的方法

Object proxy = Enhancer.create(目标对象类型 , 代理回调callback)

1.5 如何实现一个AOP

实现AOP非常简单 , 主要有两种方式 :

第一种是通过XML配置的方式实现AOP

 

 

第二种是通过注解的方式实现AOP

//日志切面类

//得加上此注解此切面类才会生效

@Aspect

public class MyLog {

//抽取公共的切入点表达式

//该表达式表明MyService类下的所有方法都加上aop功能

@Pointcut("execution(public int org.com.MyService.*(..))")

public void pointCut(){};

//在目标方法之前切入

//复用上面定义的pointCut()方法上的切入点表达式

@Before("pointCut()")

public void logStart(JoinPoint joinPoint){

    //获取目标方法名 (单纯取出来而已下面没有用到这个变量)

    String methodName = joinPoint.getSignature().getName();

    //获取目标方法参数列表 (下面有输出这个)

    Object[] args = joinPoint.getArgs();

    System.out.println("除法运行...参数列表是: {" + Arrays.asList(args) + "}");

}

//在目标方法之后切入

@After("pointCut()")

public void logEnd(){

    System.out.println("除法结束...");

}

//在目标方法正常返回切入

//result是目标方法正常返回的返回值

@AfterReturning(value = "pointCut()", returning = "result") 

public void logReturn(Object result){

    System.out.println("除法正常返回...运行结果: { " + result + " }");

}

//在目标方法异常时切入

//exception是目标方法异常的异常对象

@AfterThrowing(value = "pointCut()", throwing = "exception") 

public void logException(Exception exception){

    System.out.println("除法异常...异常信息: {" + exception+ "}");

}

}

@Aspect : 定义切面类

@Pointcut : 定义切入点表达式

@Before : 前置通知

@After : 最终通知

@AfterReturning : 后置通知

@AfterThrowing : 异常通知

1.6 Spring支持的几种bean的作用域 Scope

Spring框架支持以下五种bean的作用域:

1.singleton : bean在每个Spring ioc 容器中只有一个实例

2.prototype:一个bean的定义可以有多个实例

3.request:每次http请求都会创建一个bean

4.session:在一个HTTP Session中,一个bean定义对应一个实例

5.global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例

1.7 Spring框架中的单例bean是线程安全的吗?

不是,Spring框架中的单例bean不是线程安全的 , spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。

但是我们一般在使用单例Bean的时候, 一般这些Bean中都不会设置共享属性, 属于无状态Bean , 所以也就不会存在线程安全问题 ! 从这个角度讲单例bean也是线程安全的

1.8 讲一讲Spring中Bean创建的流程

1.BeanDefinition解析:调用容器中InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法,可以在Bean实例化前修改BeanDefinition

2.实例化:将指定的BeanDefinition转换成BeanWrapper,然后调用createBeanInstance创建Bean的实例。Bean的实例化有多种策略,如工厂方法、指定参数构造器和默认无参构造器等。总之,createBeanInstance()方法会返回一个刚实例化好的、属性未赋值的空Bean

1.属性填充:调用populateBean()方法,为Bean进行属性的赋值和依赖的注入

2.属性填充后置处理:调用容器中InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法,进行属性填充后处理

3.初始化前置处理:调用BeanPostProcessor的postProcessBeforeInitialization()方法进行初始化前置处理。

4.初始化:调用Bean的初始化方法,顺序为:InitializingBean的afterPropertiesSet() -> 注册的init-method

5.初始化后置处理:调用BeanPostProcessor的postProcessAfterInitialization()执行初始化后置处理

6.调用registerDisposableBeanIfNecessary()方法,注册Bean的销毁处理逻辑:将所有实现了DisposableBean接口的或者注册了destroy-method方法的Bean,封装成一个DisposableBean,将其销毁的回调注册到容器中

1.9 讲一讲Spring中Bean的生命周期

bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁

1.10 Spring是如何解决循环依赖的

循环依赖是指一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用 , 举个例子 : A 依赖B , B依赖C , C依赖A , 这样就形成了循环依赖

Spring解决循环依赖问题, 靠的是三级缓存机制 , Spring中的三级缓存

第一级缓存:singletonObjects,用于保存实例化、注入、初始化完成的 bean 实例

第二级缓存:earlySingletonObjects,用于保存实例化完成的 bean 实例

第三级缓存:singletonFactories,用于保存 bean 创建工厂,以便后面有机会创建代理对象

三级缓存的执行逻辑

    先从“第一级缓存”找对象,有就返回,没有就找“二级缓存”

    找“二级缓存”,有就返回,没有就找“三级缓存”

    找“三级缓存”,找到了,就获取对象,放到“二级缓存”,从“三级缓存”移除

protected Object getSingleton(String beanName, boolean allowEarlyReference) {

    //从一级缓存获取Bean

    Object singletonObject = this.singletonObjects.get(beanName);

    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {

        //从二级缓存获取Bean

        singletonObject = this.earlySingletonObjects.get(beanName);

        if (singletonObject == null && allowEarlyReference) {

            synchronized(this.singletonObjects) {

                singletonObject = this.singletonObjects.get(beanName);

                if (singletonObject == null) {

                    singletonObject = this.earlySingletonObjects.get(beanName);

                    if (singletonObject == null) {

                        //从三级缓存获取Bean工厂

                        ObjectFactory singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);

                        if (singletonFactory != null) {

                            //通过Bean工厂获取Bean对象

                            singletonObject = singletonFactory.getObject();

                            //将Bean保存到二级缓存

                            this.earlySingletonObjects.put(beanName, singletonObject);

                            //从三级缓存移除

                            this.singletonFactories.remove(beanName);

                        }

                    }

                }

            }

        }

    }

    return singletonObject;

}

三级缓存的作用 :

   一级缓存:就是个单例池,用来存放已经初始化完成的单例 Bean

   二级缓存:是为了避免因为 AOP 创建多个对象,其中存储的是半成品的 AOP 的单例 bean

   三级缓存:是为打破循环,存放的是生成半成品单例 Bean 的工厂方法

1.11 Spring中在什么情况下事物会失效

Spring中事物失效的场景很多 , 例如 :

1.因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 ! 如果使用原始对象事物会失效

2.同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效

3.如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效

4.@Transational中默认捕获的是RuntimeException , 如果没有指定捕获的异常类型, 并且程序抛出的是非运行时异常, 事物会失效

1.12 说一说@Transational的原理

1.Spring事务底层是基于数据库事务和AOP机制的

2.⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean

3.当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解

4.如果加了,那么则利⽤事务管理器创建⼀个数据库连接

5.并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步

6.然后执⾏当前⽅法,⽅法中会执⾏sql

7.执⾏完当前⽅法后,如果没有出现异常就直接提交事务

8.如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务

1.13 @Transational属性有哪些

常用的属性有 :

1.propagation : 事物传播行为

2.isolation : 事物隔离级别, 默认数据库隔离级别

3.readOnly : 是否是只读事物

4.rollbackFor : 指定哪些异常需要回滚 , 默认RuntimeException

5.noRollbackFor :  指定哪些异常不需要回滚

1.14 说一下Spring的事务传播行为有哪些

1.PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置

2.PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务

3.PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

4.PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

5.PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常

6.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常

7.PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行

1.15 @Autowired和@Resource有什么区别

@Resource和@Autowired都可以标注在字段或属性的setter方法上 , 代表自动注入 , 他们的区别主要有 :

1.提供方不同:@Autowired是由Spring提供;@Resource是由javax提供,需要JDK1.6及以上

2.注入方式不同:@Autowired只按照byType 注入;@Resource默认按byName自动注入,也提供按照byType 注入;

3.使用方式不同:@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。@Resource有两个中重要的属性:name和type。name属性指定byName,type属性指定byType

1.16 Spring中使用的设计模式有哪些

1.单例模式 : Spring中的单例Bean没有使用单例设计模式 , 但是在其他地方使用了单例设计模式 , 例如 :

org.springframework.transaction.TransactionDefinition#withDefaults

org.springframework.aop.TruePointcut#INSTANCE

org.springframework.core.OrderComparator#INSTANCE

2.构建者模式 : 主要用于构建对象, 例如 org.springframework.beans.factory.support.BeanDefinitionBuilder

org.springframework.http.ResponseEntity.HeadersBuilder

org.springframework.http.ResponseEntity.BodyBuilder

3.工厂模式 : 隐藏对象创建细节  , 例如: Spring 中的 ApplicationContext 与 BeanFactory 中的 getBean 都可以视为工厂方法

4.适配器模式 : 将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作 , Spring中典型的实现有几处:

 org.springframework.web.servlet.HandlerAdapter – 因为控制器实现有各种各样,它们的处理方法都不一样,为了统一调用,必须适配为 HandlerAdapter 接口

org.springframework.beans.factory.support.DisposableBeanAdapter – 因为销毁方法多种多样,因此都要适配为 DisposableBean 来统一调用销毁方法

org.springframework.web.servlet.handler.HandlerInterceptorAdapter : web拦截器的适配器

5.代理模式 : 通过代理对象, 控制目标对象的访问

org.springframework.aop.framework.JdkDynamicAopProxy

org.springframework.aop.framework.ObjenesisCglibAopProxy

6.装饰模式 : 对目标对象功能进行增强 , Spirng中提供的各种Wrapper结尾的类基本上都是装饰模式 , 例如 :

org.springframework.http.client.support.HttpRequestWrapper

org.springframework.web.util.ContentCachingRequestWrapper

7.观察者模式 : Spring中的一些监听器 , 基本都是使用的观察者模式 , 例如 ;

org.springframework.context.ApplicationListener

org.springframework.context.event.ApplicationEventMulticaster

org.springframework.context.ApplicationEvent

8.模版方法模式 :  Spring中一定了很多以 Template 命名的类 , 都是属于模版方法模式

大部分以 Template 命名的类,如 JdbcTemplate,TransactionTemplate



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3